home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / nslookup / list.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-27  |  19.4 KB  |  842 lines

  1. /*
  2.  * Copyright (c) 1985 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)list.c    5.13 (Berkeley) 7/23/88";
  20. #endif /* not lint */
  21.  
  22. /*
  23.  *******************************************************************************
  24.  *
  25.  *  list.c --
  26.  *
  27.  *    Routines to obtain info from name and finger servers.
  28.  *
  29.  *    Adapted from 4.3BSD BIND ns_init.c and from /usr/src/ucb/finger.c
  30.  *
  31.  *******************************************************************************
  32.  */
  33.  
  34. #include <sys/types.h>
  35. #include <sys/socket.h>
  36. #include <netinet/in.h>
  37. #include <netdb.h>
  38. #include <stdio.h>
  39. #include <strings.h>
  40. #include <ctype.h>
  41. #include <arpa/nameser.h>
  42. #include <resolv.h>
  43. #include "res.h"
  44.  
  45. /*
  46.  *  Imported from res_debug.c
  47.  */
  48. extern char *_res_resultcodes[];
  49.  
  50. typedef union {
  51.     HEADER qb1;
  52.     char qb2[PACKETSZ];
  53. } querybuf;
  54.  
  55. extern u_long         inet_addr();
  56. extern HostInfo     *defaultPtr;
  57. extern HostInfo     curHostInfo;
  58. extern int         curHostValid;
  59.  
  60. /*
  61.  *  During a listing to a file, hash marks are printed 
  62.  *  every HASH_SIZE records.
  63.  */
  64.  
  65. #define HASH_SIZE 50
  66.  
  67.  
  68. /*
  69.  *******************************************************************************
  70.  *
  71.  *  ListHosts --
  72.  *
  73.  *    Requests the name server to do a zone transfer so we
  74.  *    find out what hosts it knows about.
  75.  *
  76.  *    There are five types of output:
  77.  *    - internet addresses (default)
  78.  *    - cpu type and operating system (-h option)
  79.  *    - canonical and alias names  (-a option)
  80.  *    - well-known service names  (-s option)
  81.  *    - ALL records (-d option)
  82.  *    
  83.  *    To see all three types of information in sorted order, 
  84.  *    do the following:
  85.  *      ls domain.edu > file
  86.  *      ls -a domain.edu >> file
  87.  *      ls -h domain.edu >> file
  88.  *      ls -s domain.edu >> file
  89.  *      view file
  90.  *
  91.  *  Results:
  92.  *    SUCCESS        the listing was successful.
  93.  *    ERROR        the server could not be contacted because 
  94.  *            a socket could not be obtained or an error
  95.  *            occured while receiving, or the output file
  96.  *            could not be opened.
  97.  *
  98.  *******************************************************************************
  99.  */
  100.  
  101. int
  102. ListHosts(string, putToFile)
  103.     char *string;
  104.     int  putToFile;
  105. {
  106.     querybuf         buf;
  107.     struct sockaddr_in     sin;
  108.     HEADER             *headerPtr;
  109.     int             queryType;
  110.     int             msglen;
  111.     int             amtToRead;
  112.     int             numRead;
  113.     int             i;
  114.     int             numAnswers = 0;
  115.     int             result;
  116.     int             soacnt = 0;
  117.     u_short         len;
  118.     char             *cp, *nmp;
  119.     char             name[NAME_LEN];
  120.     char             dname[2][NAME_LEN];
  121.     char             option[NAME_LEN];
  122.     char             file[NAME_LEN];
  123.     char            *namePtr;
  124.     static char        *answer = NULL;
  125.     static int        answerLen = 0;
  126.     enum {
  127.         NO_ERRORS, 
  128.         ERR_READING_LEN, 
  129.         ERR_READING_MSG,
  130.         ERR_PRINTING,
  131.     } error = NO_ERRORS;
  132.  
  133.     /*
  134.      *  Parse the command line. It maybe of the form "ls domain",
  135.      *  "ls -a domain" or "ls -h domain".
  136.      */ 
  137.     i = sscanf(string, " ls %s %s", option, name);
  138.     if (putToFile && i == 2 && name[0] == '>') {
  139.         i--;
  140.     }
  141.     if (i == 2) {
  142.         if (strcmp("-a", option) == 0) {
  143.         queryType = T_CNAME;
  144.         } else if (strcmp("-h", option) == 0) {
  145.         queryType = T_HINFO;
  146.         } else if (strcmp("-m", option) == 0) {
  147.         queryType = T_MX;
  148.         } else if (strcmp("-s", option) == 0) {
  149.         queryType = T_WKS;
  150.         } else if (strcmp("-d", option) == 0) {
  151.         queryType = T_ANY;
  152.         } else {
  153.         queryType = T_A;
  154.         }
  155.         namePtr = name;
  156.     } else if (i == 1) {
  157.         namePtr = option;
  158.         queryType = T_A;
  159.     } else {
  160.         fprintf(stderr, "ListHosts: invalid request %s\n",string);
  161.         return(ERROR);
  162.     }
  163.  
  164.  
  165.     /*
  166.      *  Create a query packet for the requested domain name.
  167.      */
  168.     msglen = res_mkquery(QUERY, namePtr, C_IN, T_AXFR,
  169.                 (char *)0, 0, (char *)0, 
  170.                 (char *) &buf, sizeof(buf));
  171.     if (msglen < 0) {
  172.         if (_res.options & RES_DEBUG) {
  173.         fprintf(stderr, "ListHosts: Res_mkquery failed\n");
  174.         }
  175.         return (ERROR);
  176.     }
  177.  
  178.     bzero((char *)&sin, sizeof(sin));
  179.     sin.sin_family    = AF_INET;
  180.     sin.sin_port    =  htons(NAMESERVER_PORT);
  181.  
  182.     /*
  183.      *  Check to see if we have the address of the server or the
  184.      *  address of a server who knows about this domain.
  185.      *       
  186.      *  For now, just use the first address in the list.
  187.      */
  188.  
  189.     if (defaultPtr->addrList != NULL) {
  190.       sin.sin_addr = *(struct in_addr *) defaultPtr->addrList[0];
  191.     } else {
  192.       sin.sin_addr = *(struct in_addr *)defaultPtr->servers[0]->addrList[0];
  193.     }
  194.  
  195.     /*
  196.      *  Set up a virtual circuit to the server.
  197.      */
  198.     if ((sockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  199.         perror("ListHosts");
  200.         return(ERROR);
  201.     }    
  202.     if (connect(sockFD, &sin, sizeof(sin)) < 0) {
  203.         perror("ListHosts");
  204.         (void) close(sockFD);
  205.         sockFD = -1;
  206.         return(ERROR);
  207.     }    
  208.  
  209.     /*
  210.      * Send length & message for zone transfer 
  211.      */
  212.  
  213.         len = htons(msglen);
  214.  
  215.         if (write(sockFD, (char *)&len, sizeof(len)) != sizeof(len) ||
  216.             write(sockFD, (char *) &buf, msglen) != msglen) {
  217.         perror("ListHosts");
  218.         (void) close(sockFD);
  219.         sockFD = -1;
  220.         return(ERROR);
  221.     }
  222.  
  223.     fprintf(stdout,"[%s]\n",
  224.         (defaultPtr->addrList != NULL) ? defaultPtr->name : 
  225.          defaultPtr->servers[0]->name);
  226.  
  227.     if (!putToFile) {
  228.         filePtr = stdout;
  229.     } else {
  230.         filePtr = OpenFile(string, file);
  231.             if (filePtr == NULL) {
  232.                 fprintf(stderr, "*** Can't open %s for writing\n", file);
  233.         (void) close(sockFD);
  234.         sockFD = -1;
  235.                 return(ERROR);
  236.             }
  237.         fprintf(filePtr, "> %s\n", string);
  238.         fprintf(filePtr,"[%s]\n",
  239.         (defaultPtr->addrList != NULL) ? defaultPtr->name : 
  240.          defaultPtr->servers[0]->name);
  241.     }
  242.  
  243.     fprintf(filePtr, "%-30s", "Host or domain name");
  244.     switch(queryType) {
  245.         case T_ANY:
  246.             fprintf(filePtr, " %-30s\n", "Resource record info");
  247.             break;
  248.         case T_A:
  249.             fprintf(filePtr, " %-30s\n", "Internet address");
  250.             break;
  251.         case T_HINFO:
  252.             fprintf(filePtr, " %-10s %s\n", "CPU", "OS");
  253.             break;
  254.         case T_CNAME:
  255.             fprintf(filePtr, " %-30s\n", "Alias");
  256.             break;
  257.         case T_MX:
  258.             fprintf(filePtr, " %3s %s\n", "Metric", "Host");
  259.             break;
  260.         case T_WKS:
  261.             fprintf(filePtr, " %-4s %s\n", "Protocol", "Services");
  262.     }
  263.  
  264.  
  265.     while (1) {
  266.         unsigned short tmp;
  267.  
  268.         /*
  269.          * Read the length of the response.
  270.          */
  271.  
  272.         cp = (char *) &tmp;
  273.         amtToRead = sizeof(u_short);
  274.         while(amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0){
  275.         cp       += numRead;
  276.         amtToRead -= numRead;
  277.         }
  278.         if (numRead <= 0) {
  279.         error = ERR_READING_LEN;
  280.         break;
  281.         }    
  282.  
  283.         if ((len = htons(tmp)) == 0) {
  284.         break;    /* nothing left to read */
  285.         }
  286.  
  287.         /*
  288.          * The server sent too much data to fit the existing buffer --
  289.          * allocate a new one.
  290.          */
  291.         if (len > answerLen) {
  292.         if (answerLen != 0) {
  293.             free(answer);
  294.         }
  295.         answerLen = len;
  296.         answer = Malloc(answerLen);
  297.         }    
  298.  
  299.         /*
  300.          * Read the response.
  301.          */
  302.  
  303.         amtToRead = len;
  304.         cp = answer;
  305.         while(amtToRead > 0 && (numRead = read(sockFD, cp, amtToRead)) > 0){
  306.         cp += numRead;
  307.         amtToRead -= numRead;
  308.         }
  309.         if (numRead <= 0) {
  310.         error = ERR_READING_MSG;
  311.         break;
  312.         }
  313.  
  314.         result = PrintListInfo(filePtr, answer, cp, queryType);
  315.         if (result != SUCCESS) {
  316.         error = ERR_PRINTING;
  317.         break;
  318.         }
  319.  
  320.         numAnswers++;
  321.         if (putToFile && ((numAnswers % HASH_SIZE) == 0)) {
  322.         fprintf(stdout, "#");
  323.         fflush(stdout);
  324.         }
  325.         cp = answer + sizeof(HEADER);
  326.         if (ntohs(((HEADER* )answer)->qdcount) > 0)
  327.         cp += dn_skipname(cp, answer + len) + QFIXEDSZ;
  328.         nmp = cp;
  329.         cp += dn_skipname(cp, (u_char *)answer + len);
  330.         if ((_getshort(cp) == T_SOA)) {
  331.         dn_expand(answer, answer + len, nmp, dname[soacnt],
  332.             sizeof(dname[0]));
  333.             if (soacnt) {
  334.             if (strcmp(dname[0], dname[1]) == 0)
  335.             break;
  336.         } else
  337.             soacnt++;
  338.         }
  339.     }
  340.  
  341.     if (putToFile) {
  342.         fprintf(stdout, "%sReceived %d record%s.\n", 
  343.         (numAnswers >= HASH_SIZE) ? "\n" : "",
  344.         numAnswers,
  345.         (numAnswers != 1) ? "s" : "");
  346.     }
  347.  
  348.     (void) close(sockFD);
  349.     sockFD = -1;
  350.     if (putToFile) {
  351.         fclose(filePtr);
  352.         filePtr = NULL;
  353.     }
  354.  
  355.     switch (error) {
  356.         case NO_ERRORS:
  357.         return (SUCCESS);
  358.  
  359.         case ERR_READING_LEN:
  360.         return(ERROR);
  361.  
  362.         case ERR_PRINTING:
  363.         fprintf(stderr,"*** Error during listing of %s: %s\n", 
  364.                 namePtr, DecodeError(result));
  365.         return(result);
  366.  
  367.         case ERR_READING_MSG:
  368.         headerPtr = (HEADER *) answer;
  369.         fprintf(stderr,"ListHosts: error receiving zone transfer:\n");
  370.         fprintf(stderr,
  371.            "  result: %s, answers = %d, authority = %d, additional = %d\n", 
  372.                 _res_resultcodes[headerPtr->rcode], 
  373.                 ntohs(headerPtr->ancount), ntohs(headerPtr->nscount), 
  374.             ntohs(headerPtr->arcount));
  375.         return(ERROR);
  376.         default:
  377.         return(ERROR);
  378.     }
  379. }
  380.  
  381.  
  382. /*
  383.  *******************************************************************************
  384.  *
  385.  *  PrintListInfo --
  386.  *
  387.  *     Used by the ListInfo routine to print the answer 
  388.  *    received from the name server. Only the desired 
  389.  *    information is printed.
  390.  *
  391.  *  Results:
  392.  *    SUCCESS        the answer was printed without a problem.
  393.  *    NO_INFO        the answer packet did not contain an answer.
  394.  *    ERROR        the answer was malformed.
  395.  *      Misc. errors    returned in the packet header.
  396.  *
  397.  *******************************************************************************
  398.  */
  399.  
  400. #define NAME_FORMAT " %-30s"
  401. #define STRIP_DOMAIN(string) if((dot = index(string, '.')) != NULL) *dot = '\0'
  402.  
  403.  
  404. PrintListInfo(file, msg, eom, queryType)
  405.     FILE     *file;
  406.     char     *msg, *eom;
  407.     int     queryType;
  408. {
  409.     register char     *cp;
  410.     HEADER         *headerPtr;
  411.     int         type, class, dlen, nameLen;
  412.     u_long        ttl;
  413.     int         n;
  414.     struct in_addr     inaddr;
  415.     char         name[NAME_LEN];
  416.     char         name2[NAME_LEN];
  417.     char         *dot;
  418.  
  419.     /*
  420.      * Read the header fields.
  421.      */
  422.     headerPtr = (HEADER *)msg;
  423.     cp = msg + sizeof(HEADER);
  424.     if (headerPtr->rcode != NOERROR) {
  425.     return(headerPtr->rcode);
  426.     }
  427.  
  428.     /*
  429.      *  We are looking for info from answer resource records.
  430.      *  If there aren't any, return with an error. We assume
  431.      *  there aren't any question records.
  432.      */
  433.  
  434.     if (ntohs(headerPtr->ancount) == 0) {
  435.     return(NO_INFO);
  436.     } else {
  437.     if (ntohs(headerPtr->qdcount) > 0) {
  438.         nameLen = dn_skipname(cp, eom);
  439.         if (nameLen < 0)
  440.         return (ERROR);
  441.         cp += nameLen + QFIXEDSZ;
  442.     }
  443.     if ((nameLen = dn_expand(msg, eom, cp, name, sizeof(name))) < 0) {
  444.         return (ERROR);
  445.     }
  446.     cp += nameLen;
  447.     type = _getshort(cp);
  448.     cp += sizeof(u_short);
  449.     class = _getshort(cp);
  450.     cp += sizeof(u_short);
  451.     ttl = _getlong(cp);
  452.     cp += sizeof(u_long);
  453.     dlen = _getshort(cp);
  454.     cp += sizeof(u_short);
  455.     if (name[0] == 0)
  456.         strcpy(name, "(root)");
  457.  
  458.     /*
  459.      * QueryType is used to specify the type of desired information.
  460.      *  T_A       - internet address
  461.      *  T_CNAME     - aliases
  462.      *  T_HINFO    - cpu, OS type
  463.      *  T_MX    - mail routing
  464.      *  T_WKS    - well known service
  465.      *  T_ANY    - any
  466.      *
  467.      */
  468.     switch (type) {
  469.  
  470.         case T_A:
  471.         if (queryType != T_A && queryType != T_ANY)
  472.             break;
  473.  
  474.         if ((_res.options & RES_DEBUG) == 0)
  475.             STRIP_DOMAIN(name);
  476.         fprintf(file, NAME_FORMAT, name);
  477.         if (queryType == T_ANY)
  478.             fprintf(file," %-5s", p_type(type));
  479.         if (class == C_IN) {
  480.             bcopy(cp, (char *)&inaddr, sizeof(inaddr));
  481.             if (dlen == 4) {
  482.             fprintf(file," %s", inet_ntoa(inaddr));
  483.             } else if (dlen == 7) {
  484.             fprintf(file," %s", inet_ntoa(inaddr));
  485.             fprintf(file," (%d, %d)", cp[4],(cp[5] << 8) + cp[6]);
  486.             } else
  487.             fprintf(file, " (dlen = %d?)", dlen);
  488.             if (_res.options & RES_DEBUG)
  489.             fprintf(file,"\t\t\t%lu", ttl);
  490.             fprintf(file,"\n");
  491.         } else
  492.             goto other;
  493.         break;
  494.         
  495.         case T_CNAME:
  496.         if (queryType != T_CNAME && queryType != T_ANY)
  497.             break;
  498.  
  499.         if ((_res.options & RES_DEBUG) == 0)
  500.             STRIP_DOMAIN(name);
  501.         fprintf(file, NAME_FORMAT, name);
  502.         if (queryType == T_ANY)
  503.             fprintf(file," %-5s", p_type(type));
  504.         if ((nameLen = dn_expand(msg, eom, cp, name2, sizeof(name2))) < 0) {
  505.             fprintf(file, " ***\n");
  506.             return (ERROR);
  507.         }
  508.         /* 
  509.          * a bug -- cnames need not be in same domain!
  510.          * STRIP_DOMAIN(name2);
  511.          */
  512.  
  513.         fprintf(file, NAME_FORMAT, name2);
  514.         if (_res.options & RES_DEBUG)
  515.             fprintf(file,"\t%lu", ttl);
  516.         fprintf(file,"\n");
  517.         break;
  518.         
  519.         case T_HINFO:
  520.         if (queryType != T_HINFO && queryType != T_ANY)
  521.             break;
  522.  
  523.         if ((_res.options & RES_DEBUG) == 0)
  524.             STRIP_DOMAIN(name);
  525.         fprintf(file, NAME_FORMAT, name);
  526.         if (queryType == T_ANY)
  527.             fprintf(file," %-5s", p_type(type));
  528.         if (n = *cp++) {
  529.             (void)sprintf(name,"%.*s", n, cp);
  530.             fprintf(file," %-10s", name);
  531.             cp += n;
  532.         } else {
  533.             fprintf(file," %-10s", " ");
  534.         }
  535.         if (n = *cp++) {
  536.             fprintf(file," %.*s", n, cp);
  537.             cp += n;
  538.         }
  539.         if (_res.options & RES_DEBUG)
  540.             fprintf(file,"\t\t%lu", ttl);
  541.         fprintf(file,"\n");
  542.         break;
  543.  
  544.         case T_MX:
  545.         if (queryType != T_MX && queryType != T_ANY)
  546.             break;
  547.  
  548.         if ((_res.options & RES_DEBUG) == 0)
  549.             STRIP_DOMAIN(name);
  550.         fprintf(file, NAME_FORMAT, name);
  551.         if (queryType == T_ANY)
  552.             fprintf(file," %-5s", p_type(type));
  553.  
  554.         {
  555.             short pref;
  556.  
  557.             pref = _getshort(cp);
  558.             cp += sizeof(u_short);
  559.             fprintf(file," %-3d ",pref);
  560.         }
  561.         if ((nameLen = dn_expand(msg, eom, cp, name2, sizeof(name2))) < 0) {
  562.             fprintf(file, " ***\n");
  563.             return (ERROR);
  564.         }
  565.         fprintf(file, " %s", name2);
  566.         if (_res.options & RES_DEBUG)
  567.             fprintf(file,"\t%lu", ttl);
  568.         fprintf(file,"\n");
  569.  
  570.         break;
  571.  
  572.  
  573.         case T_NS:
  574.         case T_PTR:
  575.         if (queryType != T_A && queryType != T_ANY)
  576.             break;
  577.         /*
  578.          *  Found a name server or pointer record.
  579.          */
  580.         if ((_res.options & RES_DEBUG) == 0)
  581.             STRIP_DOMAIN(name);
  582.         fprintf(file, NAME_FORMAT, name);
  583.         if (queryType == T_ANY)
  584.             fprintf(file," %-5s", p_type(type));
  585.         fprintf(file," %s = ", type == T_PTR ? "host" : "server");
  586.         cp = Print_cdname2(cp, msg, eom, file);
  587.         if (_res.options & RES_DEBUG)
  588.             fprintf(file,"\t%lu", ttl);
  589.         fprintf(file,"\n");
  590.         break;
  591.  
  592.         case T_WKS:
  593.         if (queryType != T_WKS && queryType != T_ANY)
  594.             break;
  595.  
  596.         if ((_res.options & RES_DEBUG) == 0)
  597.             STRIP_DOMAIN(name);
  598.         fprintf(file, NAME_FORMAT, name);
  599.         if (queryType == T_ANY)
  600.             fprintf(file," %-5s", p_type(type));
  601.         if (class == C_IN) {
  602.             cp += 4; dlen -= 4;
  603.             {
  604.             struct protoent *pp;
  605.             struct servent *ss;
  606.             u_short port;
  607.  
  608.             setprotoent(1);
  609.             setservent(1);
  610.             n = *cp & 0377;
  611.             pp = getprotobynumber(n);
  612.             if(pp == 0)  
  613.                 fprintf(file," %-3d ", n);
  614.             else
  615.                 fprintf(file," %-3s ", pp->p_name);
  616.             cp++; dlen--;
  617.  
  618.             port = 0;
  619.             while(dlen-- > 0) {
  620.                 n = *cp++;
  621.                 do {
  622.                 if(n & 0200) {
  623.                     ss = getservbyport((int)htons(port), pp->p_name);
  624.                     if(ss == 0)  
  625.                     fprintf(file," %d", port);
  626.                     else
  627.                     fprintf(file," %s", ss->s_name);
  628.                 }
  629.                     n <<= 1;
  630.                 } while(++port & 07);
  631.             }
  632.             } 
  633.         } else
  634.             goto other;
  635.         if (_res.options & RES_DEBUG)
  636.             fprintf(file,"\t%lu", ttl);
  637.         fprintf(file,"\n");
  638.         endprotoent();
  639.         endservent();
  640.         break;
  641.  
  642.         case T_SOA:
  643.         case T_AXFR:
  644.         if (queryType != T_ANY)
  645.             break;
  646.         fprintf(file, NAME_FORMAT, name);
  647.         if (queryType == T_ANY)
  648.             fprintf(file," %-5s", p_type(type));
  649.         if ((nameLen = dn_expand(msg, eom, cp, name2, sizeof(name2))) < 0) {
  650.             fprintf(file, " ***\n");
  651.             return (ERROR);
  652.         }
  653.         cp += nameLen;
  654.         fprintf(file, " %s", name2);
  655.         if ((nameLen = dn_expand(msg, eom, cp, name2, sizeof(name2))) < 0) {
  656.             fprintf(file, " ***\n");
  657.             return (ERROR);
  658.         }
  659.         cp += nameLen;
  660.         fprintf(file, " %s. (", name2);
  661.         for (n = 0; n < 5; n++) {
  662.             u_long u;
  663.  
  664.             u = _getlong(cp);
  665.             cp += sizeof(u_long);
  666.             fprintf(file,"%s%d", n? " " : "", u);
  667.         }
  668.         fprintf(file, ")");
  669.         if (_res.options & RES_DEBUG)
  670.             fprintf(file,"\t%lu", ttl);
  671.         fprintf(file,"\n");
  672.         break;
  673.  
  674.         default:
  675.         /*
  676.          * Unwanted answer type -- ignore it.
  677.          */
  678.         if (queryType != T_ANY)
  679.             break;
  680.         if ((_res.options & RES_DEBUG) == 0)
  681.             STRIP_DOMAIN(name);
  682.         fprintf(file, NAME_FORMAT, name);
  683. other:
  684.         fprintf(file," type = %-5s", p_type(type));
  685.         fprintf(file,", class = %-5s", p_class(class));
  686.         if (_res.options & RES_DEBUG)
  687.             fprintf(file,"\t%lu\n", ttl);
  688.         break;
  689.     }
  690.     }
  691.     return(SUCCESS);
  692. }
  693.  
  694.  
  695. /*
  696.  *******************************************************************************
  697.  *
  698.  *  ViewList --
  699.  *
  700.  *    A hack to view the output of the ls command in sorted
  701.  *    order using more.
  702.  *
  703.  *******************************************************************************
  704.  */
  705.  
  706. ViewList(string)
  707.     char *string;
  708. {
  709.     char file[NAME_LEN];
  710.     char command[NAME_LEN];
  711.  
  712.     sscanf(string, " view %s", file);
  713.     (void)sprintf(command, "grep \"^ \" %s | sort | more", file);
  714.     system(command);
  715. }
  716.  
  717. /*
  718.  *******************************************************************************
  719.  *
  720.  *   Finger --
  721.  *
  722.  *    Connects with the finger server for the current host
  723.  *    to request info on the specified person (long form)
  724.  *    who is on the system (short form).
  725.  *
  726.  *  Results:
  727.  *    SUCCESS        the finger server was contacted.
  728.  *    ERROR        the server could not be contacted because 
  729.  *            a socket could not be obtained or connected 
  730.  *            to or the service could not be found.
  731.  *
  732.  *******************************************************************************
  733.  */
  734.  
  735. Finger(string, putToFile)
  736.     char *string;
  737.     int  putToFile;
  738. {
  739.     struct servent         *sp;
  740.     struct sockaddr_in     sin;
  741.     register FILE         *f;
  742.     register int         c;
  743.     register int         lastc;
  744.     char             name[NAME_LEN];
  745.     char             file[NAME_LEN];
  746.  
  747.     /*
  748.      *  We need a valid current host info to get an inet address.
  749.      */
  750.     if (!curHostValid) {
  751.         fprintf(stderr, "Finger: no current host defined.\n");
  752.         return (ERROR);
  753.     }
  754.  
  755.     if (sscanf(string, " finger %s", name) == 1) {
  756.         if (putToFile && (name[0] == '>')) {
  757.         name[0] = '\0';
  758.         }
  759.     } else {
  760.         name[0] = '\0';
  761.     }
  762.  
  763.     sp = getservbyname("finger", "tcp");
  764.     if (sp == 0) {
  765.         fprintf(stderr, "Finger: unknown service\n");
  766.         return (ERROR);
  767.     }
  768.  
  769.     bzero((char *)&sin, sizeof(sin));
  770.     sin.sin_family    = curHostInfo.addrType;
  771.     sin.sin_port    = sp->s_port;
  772.     bcopy(curHostInfo.addrList[0], (char *)&sin.sin_addr, 
  773.         curHostInfo.addrLen);
  774.  
  775.     /*
  776.      *  Set up a virtual circuit to the host.
  777.      */
  778.  
  779.     sockFD = socket(curHostInfo.addrType, SOCK_STREAM, 0);
  780.     if (sockFD < 0) {
  781.         fflush(stdout);
  782.         perror("Finger");
  783.         return (ERROR);
  784.     }
  785.  
  786.     if (connect(sockFD, (char *)&sin, sizeof (sin)) < 0) {
  787.         fflush(stdout);
  788.         perror("Finger");
  789.         close(sockFD);
  790.         sockFD = -1;
  791.         return (ERROR);
  792.     }
  793.  
  794.     if (!putToFile) {
  795.         filePtr = stdout;
  796.     } else {
  797.         filePtr = OpenFile(string, file);
  798.         if (filePtr == NULL) {
  799.         fprintf(stderr, "*** Can't open %s for writing\n", file);
  800.         close(sockFD);
  801.         sockFD = -1;
  802.         return(ERROR);
  803.         }
  804.         fprintf(filePtr,"> %s\n", string);
  805.     }
  806.     fprintf(filePtr, "[%s]\n", curHostInfo.name);
  807.  
  808.     if (name[0] != '\0') {
  809.         write(sockFD, "/W ", 3);
  810.     }
  811.     write(sockFD, name, strlen(name));
  812.     write(sockFD, "\r\n", 2);
  813.     f = fdopen(sockFD, "r");
  814.     while ((c = getc(f)) != EOF) {
  815.         switch(c) {
  816.         case 0210:
  817.         case 0211:
  818.         case 0212:
  819.         case 0214:
  820.             c -= 0200;
  821.             break;
  822.         case 0215:
  823.             c = '\n';
  824.             break;
  825.         }
  826.         putc(lastc = c, filePtr);
  827.     }
  828.     if (lastc != '\n') {
  829.         putc('\n', filePtr);
  830.     }
  831.     putc('\n', filePtr);
  832.  
  833.     close(sockFD);
  834.     sockFD = -1;
  835.  
  836.     if (putToFile) {
  837.         fclose(filePtr);
  838.         filePtr = NULL;
  839.     }
  840.     return (SUCCESS);
  841. }
  842.